// by Tyrghen
// Overriding some bDetect functions to make them more MP friendly

#include <bDetect.sqf>

bdetect_fnc_fired_wrapper = {
	//diag_log ["bdetect_fnc_fired_wrapper",_this,(local (_this select 0))];
	if !(local (_this select 0)) exitWith {};
	_this call bdetect_fnc_fired;
};

bdetect_fnc_eh_add =
{
    private ["_unit", "_vehicle", "_e", "_msg"];
	
    _unit = _this select 0;
	
	if !(local _unit) exitWith {};
	if (!isDedicated && {(!isplayer _unit && (side _unit != playerSide))}) exitWith {};
	
    _vehicle = assignedVehicle _unit;
    if( isNull _vehicle && _unit != vehicle _unit ) then { _vehicle =  vehicle _unit };
	
	if(  ( isNil { _unit getVariable "bdetect_fired_eh" }))  then
    {
        _e = _unit addEventHandler ["Fired", bdetect_fnc_fired_wrapper];
        _unit setVariable ["bdetect_fired_eh", _e]; 
        
        _e = _unit addEventHandler ["Killed", bdetect_fnc_killed];
        _unit setVariable ["bdetect_killed_eh", _e]; 
     		
        bdetect_units_count = bdetect_units_count + 1;
        
		if( bdetect_debug_enable ) then {
			_msg = format["bdetect_fnc_eh_add() - unit=%1, FIRED + KILLED EH assigned ", _unit];
			[ _msg, 3 ] call bdetect_fnc_debug;    
		};
		diag_log ["bDetect","Added EH",_unit,typeOf _unit];
    };
	
    // handling vehicles
    if( 
		!( isNull _vehicle ) 
		&& isNil { _vehicle getVariable "bdetect_fired_eh" } 
	) then {  
		
		_e = _vehicle addEventHandler ["Fired", bdetect_fnc_fired_wrapper];  
		_vehicle setVariable ["bdetect_fired_eh", _e]; 
		
		_e = _vehicle addEventHandler ["Killed", bdetect_fnc_killed];        
		_vehicle setVariable ["bdetect_killed_eh", _e]; 

		bdetect_units_count = bdetect_units_count + 1;            
		
		if( bdetect_debug_enable ) then {
			_msg = format["bdetect_fnc_eh_add() - vehicle=%1, FIRED + KILLED EH assigned", _vehicle];
			[ _msg, 3 ] call bdetect_fnc_debug;    
		};
		diag_log ["bDetect","Added EH",_vehicle,typeOf _vehicle];
    };
};

// Time-critical detection function, to be executed per-frame
bdetect_fnc_detect =         
{        
	private ["_tot", "_msg"];
	// TYRGHEN - If a client is running too low on FPS, it isn't enjoyable anymore, we ease the load by disabling the suppression detection
	if( bdetect_enable) then
	{
		if (bdetect_fps >= bdetect_fps_min) then {
			private ["_t", "_dt"];
			
			_t = time; //diag_tickTime
			_dt = _t - bdetect_frame_tstamp;

			if( _dt >= bdetect_frame_min_duration ) then
			{

				bdetect_frame_tstamp = _t;
				
				if( bdetect_debug_enable && diag_frameno % 32 == 0) then {
					_msg = format["bdetect_fnc_detect() - Frame: duration=%1 (min=%2), FPS=%3", _dt , bdetect_frame_min_duration, diag_fps ];
					[ _msg, 1 ] call bdetect_fnc_debug;
				};
				
				if( bdetect_fps_adaptation && diag_frameno % bdetect_fps_calc_each_x_frames == 0) then {
					call bdetect_fnc_diag_min_fps;
				};
				
				_tot = count bdetect_fired_bullets;

				if ( _tot > 0 ) then 
				{ 
					[ _tot, _t ] call bdetect_fnc_detect_sub;
				};
			};
			
			bdetect_fired_bullets = bdetect_fired_bullets - [-1];
		} else {			
			if( bdetect_fps_adaptation && diag_frameno % bdetect_fps_calc_each_x_frames == 0) then {
				call bdetect_fnc_diag_min_fps;
			};
			bdetect_fired_bullets = [];
		};
	};
};

bdetect_fnc_detect_sub = 
{
	private ["_tot", "_t", "_n", "_bullet", "_data", "_shooter", "_pos", "_time", "_blacklist", "_update_blacklist", "_bpos", "_dist", "_units", "_x", "_data", "_nul"];
	
	_tot = _this select 0;
	_t = _this select 1;
	
	for "_n" from 0 to _tot - 1 step 2 do 
	{
		_bullet = bdetect_fired_bullets select _n;
		_data = bdetect_fired_bullets select (_n + 1);
		_shooter = _data select 0;
		_pos = _data select 1;
		_time = _data select 2;
		_blacklist = _data select 3;
		_update_blacklist = false;
		
		if( !( isnull _bullet ) ) then
		{
			_bpos = getPosATL _bullet;
			_dist = _bpos distance _pos;	

			if( bdetect_debug_enable ) then {
				_msg = format["bdetect_fnc_detect_sub() - Flying: bullet=%1, lifespan=%2, distance=%3, speed=%4, position=%5", _bullet, _t - _time, round _dist, round (speed _bullet / 3.6), getPosATL _bullet];
				[ _msg, 2 ] call bdetect_fnc_debug;
			};
		};			

		if( isNull _bullet 
		|| !(alive _bullet) 
		|| _t - _time > bdetect_bullet_max_lifespan 
		|| _dist > bdetect_bullet_max_distance	
		|| speed _bullet < bdetect_bullet_initial_min_speed // funny rebounds handling
		|| ( ( _bpos select 2) > bdetect_bullet_max_height && ( ( vectordir _bullet ) select 2 ) > 0.2 ) 
		) then {
			
			[ _bullet ] call bdetect_fnc_bullet_tag_remove;
		}
		else
		{
			if( _dist > bdetect_bullet_min_distance	) then {
			
				_units = _bpos nearEntities [ bdetect_units_kindof, bdetect_bullet_max_proximity];
				
				{
					// TYRGHEN - Removed the F******* local check
					if( _x != _shooter && alive _x) then //&& lifestate _x == "ALIVE"
					{
			
					
						if( _x in _blacklist ) then 
						{
							bdetect_fired_bullets_count_blacklisted = bdetect_fired_bullets_count_blacklisted + 1;
							
							if( bdetect_debug_enable ) then {
								_msg = format["bdetect_fnc_detect_sub() - blacklisted: bullet=%1, unit=%2, shooter=%3", _bullet, _x, _shooter];
								[ _msg, 5 ] call bdetect_fnc_debug;
							};
						}
						else
						{
							_blacklist set [ count _blacklist, _x];
							_update_blacklist = true;
							
							bdetect_fired_bullets_count_detected = bdetect_fired_bullets_count_detected + 1;
									
							// compile callback name into function
							bdetect_callback_compiled = call compile format["%1", bdetect_callback];

							
							if( bdetect_callback_mode == "spawn" ) then {
								_nul = [ _x, _shooter, _bullet, _bpos, _pos, _time ] spawn bdetect_callback_compiled;
							} else {
								[ _x, _shooter, _bullet, _bpos, _pos, _time ] call bdetect_callback_compiled;
							};
							
							if( bdetect_debug_enable ) then {
								_msg = format["bdetect_fnc_detect_sub() - *** CLOSE BULLET ***: unit=%1, bullet=%2, shooter=%3, proximity=%4, data=%5", _x, _bullet, _shooter, round (_x distance _bpos), _data];
								[ _msg, 9 ] call bdetect_fnc_debug;
							};
						};
					};
					
				} foreach _units;
					
				if(_update_blacklist) then {
					bdetect_fired_bullets set[ _n + 1, [_shooter, _pos, _time, _blacklist] ]; // Update blacklist
				};
			};
		};
	};
};